home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / UTILITIES / copyifdifferent.c next >
C/C++ Source or Header  |  1989-12-20  |  6KB  |  247 lines

  1. /*
  2.  * copyifdifferent.c
  3.  *
  4.  * Demers, December 20, 1989 9:00:32 am PST
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <sys/file.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/time.h>
  12. #include <string.h>
  13.  
  14. #define BUFBYTES 8192
  15.  
  16. char *pgmName;
  17. int pflag = 0;    /* preserve uid/gid/mtime */
  18. int vflag = 0;    /* verbose */
  19. int returnCode = 0;
  20.  
  21.  
  22. void
  23. SetReturnCode(n)
  24.     int n;
  25. {
  26.     if( returnCode < n ) returnCode = n;
  27. }
  28.  
  29.  
  30. int
  31. IsDirectory(name)
  32.     char *name;
  33. {
  34.     struct stat buf;
  35.  
  36.     if( stat(name, &buf) < 0 ) return(0);
  37.     return( (buf.st_mode & S_IFDIR) != 0 );
  38. }
  39.  
  40.  
  41. char *
  42. MakeDestFileName(srcName, destDirName)
  43.     char *srcName;
  44.     char *destDirName;
  45. {
  46.     char *answer;
  47.     char *p;
  48.     answer = (char *)(malloc( strlen(srcName) + strlen(destDirName) + 2 ));
  49.     (void)strcpy(answer, destDirName);
  50.     (void)strcat(answer, "/");
  51.     p = strrchr(srcName, '/');
  52.     if( p != NULL ) { p += 1; } else { p = srcName; }
  53.     (void)strcat(answer, p);
  54.     return( answer );
  55. }
  56.  
  57.  
  58. int
  59. FirstDifference(p, q, n)
  60.     char *p;
  61.     char *q;
  62.     int n;
  63. {
  64.     int i;
  65.     for( i = 0; i < n; i++ )
  66.         if( *p++ != *q++ ) return(i);
  67.     return(-1);
  68. }
  69.  
  70. void
  71. DoOneFile(srcName, destName)
  72.     char *srcName;
  73.     char *destName;
  74. {
  75.     int srcfd = -1;
  76.     int destfd = -1;
  77.     char srcbuf[BUFBYTES];
  78.     char destbuf[BUFBYTES];
  79.     int srccnt, destcnt, i;
  80.     struct stat srcstat;
  81.     struct stat deststat;
  82.     unsigned filepos = 0;
  83.  
  84.     if( vflag ) printf("%s: ", srcName);
  85.     srcfd = open(srcName, O_RDONLY, 0);
  86.     if( srcfd < 0 ) {
  87.         if( vflag ) printf("cannot open.\n");
  88.         perror(srcName);
  89.         SetReturnCode(1);
  90.         goto Out;
  91.     }
  92.     (void)fstat(srcfd, &srcstat);
  93.     destfd = open(destName, O_RDONLY, 0);
  94.     if( destfd > 0 ) {
  95.         if( vflag ) printf("comparing to %s ... ", destName);
  96.         (void)fstat(destfd, &deststat);
  97.         if( srcstat.st_size != deststat.st_size ) {
  98.             if( vflag ) printf("lengths differ; ");
  99.             goto DiffFound;
  100.         }
  101.         for(;;) {
  102.             srccnt = read(srcfd, srcbuf, BUFBYTES);
  103.             destcnt = read(destfd, destbuf, BUFBYTES);
  104.             if( (srccnt < 0) || (destcnt < 0 ) ) {
  105.                 if( vflag ) printf("I/O error\n");
  106.                 perror(((srccnt < 0) ? srcName : destName));
  107.                 SetReturnCode(1);
  108.                 goto Out;
  109.             }
  110.             if( srccnt != destcnt ) {
  111.                 if( vflag ) printf("premature EOF\n");
  112.                 fprintf(stderr,"%s: %s/%s premature EOF\n",
  113.                         pgmName, srcName, destName);
  114.                 SetReturnCode(1);
  115.                 goto Out;
  116.             }
  117.             if( srccnt == 0 ) {
  118.                 if( vflag ) printf("files identical\n");
  119.                 goto Out;
  120.             }
  121.             i = FirstDifference(srcbuf, destbuf, srccnt);
  122.             if( i >= 0 ) {
  123.                 if( vflag ) printf("files differ at %d; ", filepos+i);
  124.                 goto DiffFound;
  125.             }
  126.             filepos += srccnt;
  127.         }
  128.         /*NOTREACHED*/
  129.     } else {
  130.         if( vflag ) printf("%s nonexistent; ", destName);
  131.         goto DiffFound;
  132.     }
  133.  
  134. DiffFound: ;
  135.     (void) close(destfd);
  136.     if( vflag ) printf("copying ... ");
  137.     destfd = open(destName, (O_RDWR|O_CREAT), srcstat.st_mode&07777);
  138.     if( destfd < 0 ) {
  139.         if( vflag ) printf("cannot create\n");
  140.         perror(destName);
  141.         SetReturnCode(1);
  142.         goto Out;
  143.     }
  144.     (void)lseek(srcfd, filepos, L_SET);
  145.     (void)lseek(destfd, filepos, L_SET);
  146.     for(;;) {
  147.         srccnt = read(srcfd, srcbuf, BUFBYTES);
  148.         if( srccnt == 0 ) break;
  149.         if( srccnt > 0 ) {
  150.             filepos += srccnt;
  151.             destcnt = write(destfd, srcbuf, srccnt);
  152.             if( destcnt == srccnt ) continue;
  153.         }
  154.         if( vflag ) printf("I/O error\n");
  155.         fprintf(stderr, "%s: %s, %s I/O error\n",
  156.                 pgmName, srcName, destName);
  157.         SetReturnCode(1);
  158.         goto Out;
  159.     }
  160.     destcnt = ftruncate(destfd, filepos);
  161.     if( destcnt < 0 ) {
  162.         if( vflag ) printf("truncate error\n");
  163.         perror(destName);
  164.         SetReturnCode(1);
  165.         goto Out;
  166.     }
  167.     if( pflag ) {
  168.         struct timeval tvp[2];
  169.     /* change time */
  170.         tvp[0].tv_sec = srcstat.st_atime; 
  171.         tvp[0].tv_usec = 0;
  172.         tvp[1].tv_sec = srcstat.st_mtime;
  173.         tvp[1].tv_usec = 0;
  174.         if( utimes(destName, tvp) < 0 ) {
  175.             if( vflag ) printf("can't set times\n");
  176.             perror(destName);
  177.             SetReturnCode(1);
  178.                 goto Out;
  179.             }
  180.     /* change uid/gid */
  181.         if( fchown(destfd, srcstat.st_uid, srcstat.st_gid) < 0 ) {
  182.         if( vflag ) printf("can't chown\n");
  183.         if( getuid() == 0 ) {
  184.             perror(destName);
  185.                 SetReturnCode(1);
  186.                     goto Out;
  187.                 } else {
  188.                     printf("warning: can't chown (not root)\n");
  189.                 }
  190.         }
  191.     }
  192.     if( vflag ) printf("done\n");
  193.  
  194. Out:
  195.     (void) close(srcfd);
  196.     (void) close(destfd);
  197. }
  198.  
  199.  
  200. void
  201. Usage(msg)
  202.     char *msg;
  203. {
  204.     if( msg ) fprintf(stderr, "%s: %s.\n", pgmName, msg);
  205.     fprintf(stderr, "Usage: %s [-v] [-p] from to\n", pgmName);
  206.     fprintf(stderr, "Usage: %s [-v] [-p] from1 ... fromn todir\n", pgmName);
  207.     exit(-1);
  208. }
  209.  
  210. main(argc, argv)
  211.     int argc;
  212.     char **argv;
  213. {
  214.     int i, isDir;
  215.  
  216.     pgmName = argv[0];
  217.     argv += 1;  argc -= 1;
  218.     for(;;) {
  219.     if( argc < 1 ) break;
  220.     if( (*argv)[0] != '-' ) break;
  221.     switch((*argv)[1]) {
  222.         case 'v':
  223.             vflag = 1;
  224.             break;
  225.         case 'p':
  226.             pflag = 1;
  227.             break;
  228.         default:
  229.             Usage("bad flag");
  230.     }
  231.     argv += 1;  argc -= 1;
  232.     }
  233.     if( argc < 2 ) Usage("not enough arguments");
  234.     isDir = IsDirectory(argv[argc-1]);
  235.     if( (argc > 2) && (!isDir) ) Usage("last arg not directory");
  236.     if( isDir ) {
  237.     argc -= 1;
  238.         for( i = 0; i < argc; i++ ) {
  239.             DoOneFile(argv[i], MakeDestFileName(argv[i], argv[argc]));
  240.         }
  241.     } else {
  242.         DoOneFile(argv[0], argv[1]);
  243.     }
  244.     exit(returnCode);
  245. }
  246.  
  247.